#ifndef _LIST_H_
#define _LIST_H_

#define NULL 0
#define size_t int

typedef struct listNode
{
	struct listNode *next;
	struct listNode *prev;
} listNode;

typedef struct ListHead
{
	unsigned int count;
	listNode *headNode;
	listNode *tailNode;
} listHead;

#ifdef __compiler_offsetof 
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) 
#else 
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 
#endif 

#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );}) 

#define list_entry(ptr, type, member) container_of(ptr, type, member)

/*
* define list<type> struct define
* so we can define different list with different data type
* XXX define a struct that should be include in list node
* YYY defilen a key for searching and sort that should be include in list node 
* ZZZ define a struct that should be include in the list struct 
*/
#define DEF_LIST_WITH_TYPE(XXX, YYY, ZZZ) \
typedef struct list_node_##XXX\
{\
   	struct listNode node;\
   	YYY key;\
   	XXX data;\  	
} list_node_##XXX;\
\
typedef struct XXX##_list\
{\
 	struct ListHead list_head;\
 	\
 	ZZZ list_config;\
} XXX##_list;

/*
*MICROS to declare list functions
* XXX define a struct that should be include in list node
* YYY defilen a key for searching and sort that should be include in list node 
* ZZZ define a struct that should be include in the list struct 
*/
#define DECLARE_LIST_FUNCIONS(XXX, YYY, ZZZ)\
\
void init_##XXX##_list(XXX##_list *list_ptr);\
int set_config_##XXX##_list(XXX##_list *list_ptr, ZZZ *cfg_ptr);\
list_node_##XXX * find_##XXX##_node(YYY key, XXX##_list *list_ptr);\
list_node_##XXX * get_first_##XXX##_node(XXX##_list *list_ptr);\
list_node_##XXX * get_last_##XXX##_node(XXX##_list *list_ptr);\
list_node_##XXX * get_next_##XXX##_node(list_node_##XXX *node_ptr);\
list_node_##XXX * get_prev_##XXX##_node(list_node_##XXX *node_ptr);\
int delete_##XXX##_node(list_node_##XXX *node_ptr, XXX##_list *list_ptr);\
int insert_into_##XXX##_list_head(list_node_##XXX *node_ptr, XXX##_list *list_ptr);\
int insert_into_##XXX##_list_tail(list_node_##XXX *node_ptr, XXX##_list *list_ptr);\
int insert_into_##XXX##_list(list_node_##XXX *node_ptr, XXX##_list *list_ptr, list_node_##XXX *prev_node_ptr, list_node_##XXX *next_node_ptr);\
int release_##XXX##_list(XXX##_list *list_ptr);\
uint32 get_##XXX##_list_node_count(XXX##_list *list_ptr);

/*
 *define functions for list struct
 *
 */
#define DEF_LIST_FUNCTIONS(XXX, YYY, ZZZ)\
\
int \
init_##XXX##_list(XXX##_list *list_ptr)\
{\
	if(!list_ptr)\
		return -1;\
	return (initListHead(&list_ptr->list_head));\
}\
\
int \
set_config_##XXX##_list(XXX##_list *list_ptr, ZZZ *cfg_ptr)\
{\
	if(!list_ptr || !cfg_ptr)\
		return -1;\
	memcpy(&list_ptr->list_config, cfg_ptr, sizeof(ZZZ));\
	return 0;\
}\
\
list_node_##XXX * \
find_##XXX##_node(YYY key, XXX##_list *list_ptr)\
{\
	listNode *link_node_ptr = NULL;\
 	list_node_##XXX *node_ptr = NULL;\
	if(!list_ptr)\
		return NULL;\
	link_node_ptr = firstNode(&list_ptr->list_head);\
	while(link_node_ptr)\
	{\
		node_ptr = list_entry(link_node_ptr, list_node_##XXX, node);\
		if(node_ptr->key == key)\
		{\
			return (node_ptr);\
		}\
		link_node_ptr = nextListNode(link_node_ptr);\
	}\
	return NULL;\
}\
\
list_node_##XXX * \
get_first_##XXX##_node(XXX##_list *list_ptr)\
{\
	listNode *link_node_ptr = NULL;\
	if(!list_ptr)\
		return NULL;\
	if(!(link_node_ptr = firstNode(&list_ptr->list_head)))\
		return NULL;\
	return list_entry(link_node_ptr, list_node_##XXX, node) ;\
}\
\
list_node_##XXX * \
get_last_##XXX##_node(XXX##_list *list_ptr)\
{\
	listNode *link_node_ptr = NULL;\
	if(!list_ptr)\
		return NULL;\
	if(!(link_node_ptr = lastNode(&list_ptr->list_head)))\
		return NULL;\
	return list_entry(link_node_ptr, list_node_##XXX, node) ;\
}\
\
list_node_##XXX * \
get_next_##XXX##_node(list_node_##XXX *node_ptr)\
{\
	listNode *link_node_ptr = NULL;\
	if(!node_ptr)\
		return NULL;\
	if(!(link_node_ptr = nextListNode(&node_ptr->node)))\
		return NULL;\
	return list_entry(link_node_ptr, list_node_##XXX, node) ;\
}\
\
list_node_##XXX * \
get_prev_##XXX##_node(list_node_##XXX *node_ptr)\
{\
	listNode *link_node_ptr = NULL;\
	if(!node_ptr)\
		return NULL;\
	if(!(link_node_ptr = prevListNode(&node_ptr->node)))\
		return NULL;\
	return list_entry(link_node_ptr, list_node_##XXX, node) ;\
}\
\
int \
delete_##XXX##_node(list_node_##XXX *node_ptr, XXX##_list *list_ptr)\
{\
	if(!node_ptr)\
		return -1;\
	delListNode(&node_ptr->node, &list_ptr->list_head);\
	free(node_ptr);\
	return 0;\
}\
int \
remove_##XXX##_node(list_node_##XXX *node_ptr, XXX##_list *list_ptr)\
{\
	if(!node_ptr)\
		return -1;\
	delListNode(&node_ptr->node, &list_ptr->list_head);\
	return 0;\
}\
\
int \
insert_into_##XXX##_list_head(list_node_##XXX *node_ptr, XXX##_list *list_ptr)\
{\
	if(!node_ptr || !list_ptr)\
		return -1;\
	addListNodeHead(&node_ptr->node, &list_ptr->list_head);\
	return 0;\
}\
\
int \
insert_into_##XXX##_list_tail(list_node_##XXX *node_ptr, XXX##_list *list_ptr)\
{\
	if(!node_ptr || !list_ptr)\
		return -1;\
	addListNodeTail(&node_ptr->node, &list_ptr->list_head);\
	return 0;\
}\
\
int \
insert_into_##XXX##_list(list_node_##XXX *node_ptr, XXX##_list *list_ptr, list_node_##XXX *prev_node_ptr, list_node_##XXX *next_node_ptr)\
{\
	if(!node_ptr || !list_ptr || !prev_node_ptr || !next_node_ptr)\
		return -1;\
	addListNode(&node_ptr->node, &prev_node_ptr->node, &next_node_ptr->node, &list_ptr->list_head);\
	return 0;\
}\
\
uint32 \
get_##XXX##_list_node_count(XXX##_list *list_ptr)\
{\
	if(!list_ptr)\
		return 0;\
	return list_ptr->list_head.count;\
}\
int \
release_##XXX##_list(XXX##_list *list_ptr)\
{\
	listNode *link_node_ptr = NULL;\
 	list_node_##XXX *node_ptr = NULL;\
	if(!list_ptr)\
		return -1;\
	link_node_ptr = firstNode(&list_ptr->list_head);\
	while(link_node_ptr)\
	{\
		node_ptr = list_entry(link_node_ptr, list_node_##XXX, node);\
		link_node_ptr = nextListNode(link_node_ptr);\
		delete_##XXX##_node(node_ptr, list_ptr);\
	}\
	return 0;\
} 



/*
* functions
*/
int  initListHead(listHead *list);

extern listNode * nextListNode(listNode *currentNode);
extern listNode * prevListNode(listNode *currentNode);
extern listNode * firstNode(listHead *list);
extern listNode * lastNode(listHead *list);
extern void 	  addListNode(listNode *new, listNode *prev, listNode *next, listHead *list);
extern void 	  addListNodeHead(listNode *newNode, listHead *list);
extern void		addListNodeTail(listNode *newNode, listHead *list);

extern void		  _delListNode(listNode *prev, listNode *next, listHead *list);
extern void		  delListNode(listNode *delNode, listHead *list);

#endif//_LIST_H_
